package com.pt.chitra.view.editView.view
{
	import flash.events.EventDispatcher;
	import flash.filters.BitmapFilter;
	import flash.filters.ColorMatrixFilter;
	
	public class ColorMatrixApplier extends EventDispatcher 
	{
		
		private var _filter:ColorMatrixFilter;
		private var _paramString:String;
		
		private var _matrix:Array;
		
		private var isContrast:Boolean;
		private var isBrightness:Boolean;
		private var isSaturation:Boolean;
		private var isHue:Boolean;;
		
		// ------- Constructor -------
		public function ColorMatrixApplier(matrix:Array = null)
		{
			if (matrix == null)
			{
				resetMatrix();
			}
			else
			{
				_matrix = matrix;
			}
			
			_filter = new ColorMatrixFilter(_matrix);
		}
		
		
		public function getFilter():BitmapFilter
		{
			return _filter;
		}
		
		
		
		
		
		// ------- Public properties -------
		public function get matrix():Array
		{
			return _matrix;
		}
		
		
		public function valuesToSet(contrastVal:Boolean,brightnessVal:Boolean,saturationVal:Boolean,hueVal:Boolean):void
		{
			resetValues()
			isContrast = contrastVal;
			isBrightness = brightnessVal;
			isSaturation = saturationVal;
			isHue = hueVal;
		}
		
		private function resetValues():void
		{
			isContrast = false;
			isBrightness = false;
			isSaturation = false;
			isHue = false;
		}
		
		// ------- Public methods -------
		public function modifyFilterBasic(contrast:Number, brightness:Number, saturation:Number, hue:Number):ColorMatrixFilter
		{
			// calculate the combined matrix using the preset values
			//resetMatrix();
			if(isHue)
				setHue(hue);
			if(isSaturation)
				setSaturation(saturation);
			if(isContrast)
				setContrast(contrast);
			if(isBrightness)
				setBrightness(brightness);
			
			return new ColorMatrixFilter(_matrix);
		}
		
		
		
		
		
		// ------- Color adjustments -------
		private function resetMatrix():void
		{
			_matrix = [1, 0, 0, 0, 0,
					   0, 1, 0, 0, 0,
					   0, 0, 1, 0, 0,
					   0, 0, 0, 1, 0];
		}
		
		
		public function resetToOriginal():ColorMatrixFilter
		{
				resetMatrix();
				return new ColorMatrixFilter(_matrix);
		}
		
		private function setBrightness(value:Number):void
		{
			// convert the value to a percentage of 255
			var brightness:Number = (value / 100) * 255;
			
			var matrix:Array =  [1, 0, 0, 0, brightness,
								  0, 1, 0, 0, brightness,
								  0, 0, 1, 0, brightness,
								  0, 0, 0, 1, 0];
			
			_matrix = mMultiply(_matrix, matrix);
		}
		
		
		// takes a contrast value between -100 and 100
		private function setContrast(value:Number):void
		{
			var base:Number = value / 100;
			var multiplier:Number = 1 + ((value > 0) ? 4 * base : base);
			var offset:Number = (-128 * base) * ((value > 0) ? 5 : 1);
			var matrix:Array = [multiplier, 0, 0, 0, offset,
								 0, multiplier, 0, 0, offset,
								 0, 0, multiplier, 0, offset,
								 0, 0, 0, 1, 0];
			
			_matrix = mMultiply(_matrix, matrix);
		}
		
		
		// takes a saturation value between -100 and 100
		private function setSaturation(value:Number):void
		{
			var saturation:Number = 1 + ((value > 0) ? 3 * (value / 100) : (value / 100));
			
			var rWeight:Number = 0.212671;
			var gWeight:Number = 0.715160;
			var bWeight:Number = 0.072169;
			var baseSat:Number = 1 - saturation;
			var rSat:Number = (baseSat * rWeight) + saturation;
			var r:Number = baseSat * rWeight;
			var gSat:Number = (baseSat * gWeight) + saturation;
			var g:Number = baseSat * gWeight;
			var bSat:Number = (baseSat * bWeight) + saturation;
			var b:Number = baseSat * bWeight;
			
			var matrix:Array = [rSat, g, b, 0, 0,
								 r, gSat, b, 0, 0,
								 r, g, bSat, 0, 0,
								 0, 0, 0, 1, 0];
			
			_matrix = mMultiply(_matrix, matrix);
		}
		
		
		// takes a hue value (an angle) between -180 and 180 degrees
		private function setHue(value:Number):void
		{
			var angle:Number = value * Math.PI / 180;
			
			var c:Number = Math.cos(angle);
            var s:Number = Math.sin(angle);
			
            var lumR:Number = 0.213;
            var lumG:Number = 0.715;
            var lumB:Number = 0.072;
			
            var matrix:Array = [lumR + (c * (1 - lumR)) + (s * (-lumR)), lumG + (c * (-lumG)) + (s * (-lumG)), lumB + (c * (-lumB)) + (s * (1 - lumB)), 0, 0,
								 lumR + (c * (-lumR)) + (s * 0.143), lumG + (c * (1 - lumG)) + (s * 0.14), lumB + (c * (-lumB)) + (s * (-0.283)), 0, 0,
								 lumR + (c * (-lumR)) + (s * (-(1 - lumR))), lumG + (c * (-lumG)) + (s * lumG), lumB + (c * (1 - lumB)) + (s * lumB), 0, 0,
								 0, 0, 0, 1, 0];
			
			_matrix = mMultiply(_matrix, matrix);
		}
		
		
		// Performs matrix multiplication between two 4x5 matrices
		private static function mMultiply(m1:Array, m2:Array):Array
		{
			var result:Array = new Array(20);
			
			for (var row:int = 0; row < 19; row += 5)
			{
				for (var col:int = 0; col < 5; col++)
				{
					var cell:Number = (m1[row] * m2[col]) + (m1[row + 1] * m2[col + 5]) + (m1[row + 2] * m2[col + 10]) + (m1[row + 3] * m2[col + 15]);
					if (col == 4)
					{
						cell += m1[row + 4];
					}
					result[row + col] = cell;
				}
			}
			
			return result;
		}
	}
}